#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
音频文件处理器模块，提供音频文件的读取、保存、转换、剪辑等功能
"""

import os
import io
import tempfile
from pathlib import Path
from typing import Union, List, Dict, Optional, Tuple, Any, BinaryIO

from ..exception.exceptions import FileException
from ..logger.logger import get_logger
from ..exception.decorators import exception_handler

logger = get_logger(__name__)


class AudioFileHandler:
    """
    音频文件处理器，提供音频文件的读取、保存、转换、剪辑等功能
    
    该类需要安装pydub库：pip install pydub
    对于某些功能，还需要安装ffmpeg
    
    Attributes:
        None
    """
    
    def __init__(self):
        """
        初始化音频文件处理器
        
        Raises:
            ImportError: 如果未安装pydub库则抛出
        """
        try:
            from pydub import AudioSegment
            self.AudioSegment = AudioSegment
            logger.info("音频文件处理器初始化成功")
        except ImportError:
            raise ImportError("使用AudioFileHandler需要安装pydub库: pip install pydub")
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def load_audio(self, audio_path: Union[str, Path]) -> Any:
        """
        加载音频文件
        
        Args:
            audio_path: 音频文件路径
            
        Returns:
            pydub.AudioSegment: 音频片段对象
            
        Raises:
            FileException: 文件不存在或加载失败时抛出
        
        Examples:
            >>> handler = AudioFileHandler()
            >>> audio = handler.load_audio('example.mp3')
            >>> print(f"音频长度: {len(audio) / 1000} 秒")
        """
        audio_path = Path(audio_path)
        
        if not audio_path.exists():
            raise FileException(f"音频文件不存在: {audio_path}")
        
        try:
            # 根据文件扩展名确定格式
            format = audio_path.suffix.lower().lstrip('.')
            if not format:
                raise FileException(f"无法确定音频格式: {audio_path}")
            
            # 加载音频文件
            audio = self.AudioSegment.from_file(str(audio_path), format=format)
            logger.debug(f"音频文件加载成功: {audio_path}")
            return audio
        except Exception as e:
            raise FileException(f"加载音频文件失败: {e}")
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def save_audio(self, audio: Any, output_path: Union[str, Path], 
                  format: str = None, bitrate: str = '192k', **kwargs) -> None:
        """
        保存音频到文件
        
        Args:
            audio: pydub.AudioSegment对象
            output_path: 输出文件路径
            format: 音频格式，默认为None（根据文件扩展名自动确定）
            bitrate: 比特率，默认为'192k'
            **kwargs: 传递给pydub.AudioSegment.export()的其他参数
            
        Raises:
            FileException: 保存失败时抛出
        
        Examples:
            >>> handler = AudioFileHandler()
            >>> audio = handler.load_audio('input.mp3')
            >>> handler.save_audio(audio, 'output.wav', format='wav')
        """
        output_path = Path(output_path)
        
        # 确保输出目录存在
        output_path.parent.mkdir(parents=True, exist_ok=True)
        
        try:
            # 如果未指定格式，根据文件扩展名确定
            if format is None:
                format = output_path.suffix.lstrip('.').lower()
                if not format:
                    format = 'mp3'  # 默认格式
            
            # 保存音频
            audio.export(str(output_path), format=format, bitrate=bitrate, **kwargs)
            logger.info(f"音频保存成功: {output_path}")
        except Exception as e:
            raise FileException(f"保存音频失败: {e}")
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def convert_format(self, audio_path: Union[str, Path], output_path: Union[str, Path], 
                       format: str = None, bitrate: str = '192k', **kwargs) -> None:
        """
        转换音频格式
        
        Args:
            audio_path: 输入音频文件路径
            output_path: 输出音频文件路径
            format: 输出音频格式，默认为None（根据输出文件扩展名自动确定）
            bitrate: 比特率，默认为'192k'
            **kwargs: 传递给pydub.AudioSegment.export()的其他参数
            
        Raises:
            FileException: 文件不存在或转换失败时抛出
        
        Examples:
            >>> handler = AudioFileHandler()
            >>> handler.convert_format('input.mp3', 'output.wav')
            >>> handler.convert_format('input.mp3', 'output.ogg', bitrate='256k')
        """
        # 加载音频
        audio = self.load_audio(audio_path)
        
        # 保存为新格式
        self.save_audio(audio, output_path, format=format, bitrate=bitrate, **kwargs)
        logger.info(f"音频格式转换成功: {audio_path} -> {output_path}")
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def trim_audio(self, audio_path: Union[str, Path], output_path: Union[str, Path], 
                  start_ms: int, end_ms: int, format: str = None) -> None:
        """
        剪辑音频
        
        Args:
            audio_path: 输入音频文件路径
            output_path: 输出音频文件路径
            start_ms: 起始时间（毫秒）
            end_ms: 结束时间（毫秒）
            format: 输出音频格式，默认为None（根据输出文件扩展名自动确定）
            
        Raises:
            FileException: 文件不存在或剪辑失败时抛出
        
        Examples:
            >>> handler = AudioFileHandler()
            >>> # 剪辑从1秒到5秒的部分
            >>> handler.trim_audio('input.mp3', 'output.mp3', 1000, 5000)
        """
        # 加载音频
        audio = self.load_audio(audio_path)
        
        try:
            # 剪辑音频
            trimmed_audio = audio[start_ms:end_ms]
            
            # 保存音频
            self.save_audio(trimmed_audio, output_path, format=format)
            logger.info(f"音频剪辑成功: {audio_path} -> {output_path} ({start_ms}ms - {end_ms}ms)")
        except Exception as e:
            raise FileException(f"剪辑音频失败: {e}")
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def concatenate_audio(self, audio_paths: List[Union[str, Path]], output_path: Union[str, Path], 
                         format: str = None, crossfade_ms: int = 0) -> None:
        """
        连接多个音频文件
        
        Args:
            audio_paths: 输入音频文件路径列表
            output_path: 输出音频文件路径
            format: 输出音频格式，默认为None（根据输出文件扩展名自动确定）
            crossfade_ms: 交叉淡入淡出时长（毫秒），默认为0（无交叉淡入淡出）
            
        Raises:
            FileException: 文件不存在或连接失败时抛出
        
        Examples:
            >>> handler = AudioFileHandler()
            >>> handler.concatenate_audio(['part1.mp3', 'part2.mp3', 'part3.mp3'], 'combined.mp3')
            >>> # 带有100毫秒交叉淡入淡出的连接
            >>> handler.concatenate_audio(['part1.mp3', 'part2.mp3'], 'combined.mp3', crossfade_ms=100)
        """
        if not audio_paths:
            raise FileException("音频文件路径列表不能为空")
        
        try:
            # 加载所有音频文件
            audio_segments = [self.load_audio(path) for path in audio_paths]
            
            # 连接音频
            if crossfade_ms > 0 and len(audio_segments) > 1:
                # 使用交叉淡入淡出连接
                combined = audio_segments[0]
                for segment in audio_segments[1:]:
                    combined = combined.append(segment, crossfade=crossfade_ms)
            else:
                # 直接连接
                combined = sum(audio_segments)
            
            # 保存音频
            self.save_audio(combined, output_path, format=format)
            logger.info(f"音频连接成功: {len(audio_paths)} 个文件 -> {output_path}")
        except Exception as e:
            raise FileException(f"连接音频失败: {e}")
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def adjust_volume(self, audio_path: Union[str, Path], output_path: Union[str, Path], 
                     gain_db: float, format: str = None) -> None:
        """
        调整音频音量
        
        Args:
            audio_path: 输入音频文件路径
            output_path: 输出音频文件路径
            gain_db: 增益值（分贝），正值增加音量，负值降低音量
            format: 输出音频格式，默认为None（根据输出文件扩展名自动确定）
            
        Raises:
            FileException: 文件不存在或调整失败时抛出
        
        Examples:
            >>> handler = AudioFileHandler()
            >>> handler.adjust_volume('input.mp3', 'output.mp3', 3.0)  # 增加3dB
            >>> handler.adjust_volume('input.mp3', 'output.mp3', -6.0)  # 降低6dB
        """
        # 加载音频
        audio = self.load_audio(audio_path)
        
        try:
            # 调整音量
            adjusted_audio = audio + gain_db
            
            # 保存音频
            self.save_audio(adjusted_audio, output_path, format=format)
            logger.info(f"音频音量调整成功: {audio_path} -> {output_path} (增益: {gain_db}dB)")
        except Exception as e:
            raise FileException(f"调整音频音量失败: {e}")
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def fade_in(self, audio_path: Union[str, Path], output_path: Union[str, Path], 
               duration_ms: int, format: str = None) -> None:
        """
        添加淡入效果
        
        Args:
            audio_path: 输入音频文件路径
            output_path: 输出音频文件路径
            duration_ms: 淡入时长（毫秒）
            format: 输出音频格式，默认为None（根据输出文件扩展名自动确定）
            
        Raises:
            FileException: 文件不存在或处理失败时抛出
        
        Examples:
            >>> handler = AudioFileHandler()
            >>> handler.fade_in('input.mp3', 'output.mp3', 2000)  # 2秒淡入
        """
        # 加载音频
        audio = self.load_audio(audio_path)
        
        try:
            # 添加淡入效果
            faded_audio = audio.fade_in(duration_ms)
            
            # 保存音频
            self.save_audio(faded_audio, output_path, format=format)
            logger.info(f"音频添加淡入效果成功: {audio_path} -> {output_path} (时长: {duration_ms}ms)")
        except Exception as e:
            raise FileException(f"添加淡入效果失败: {e}")
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def fade_out(self, audio_path: Union[str, Path], output_path: Union[str, Path], 
                duration_ms: int, format: str = None) -> None:
        """
        添加淡出效果
        
        Args:
            audio_path: 输入音频文件路径
            output_path: 输出音频文件路径
            duration_ms: 淡出时长（毫秒）
            format: 输出音频格式，默认为None（根据输出文件扩展名自动确定）
            
        Raises:
            FileException: 文件不存在或处理失败时抛出
        
        Examples:
            >>> handler = AudioFileHandler()
            >>> handler.fade_out('input.mp3', 'output.mp3', 3000)  # 3秒淡出
        """
        # 加载音频
        audio = self.load_audio(audio_path)
        
        try:
            # 添加淡出效果
            faded_audio = audio.fade_out(duration_ms)
            
            # 保存音频
            self.save_audio(faded_audio, output_path, format=format)
            logger.info(f"音频添加淡出效果成功: {audio_path} -> {output_path} (时长: {duration_ms}ms)")
        except Exception as e:
            raise FileException(f"添加淡出效果失败: {e}")
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def change_speed(self, audio_path: Union[str, Path], output_path: Union[str, Path], 
                    speed_factor: float, format: str = None) -> None:
        """
        改变音频播放速度（同时改变音调）
        
        Args:
            audio_path: 输入音频文件路径
            output_path: 输出音频文件路径
            speed_factor: 速度因子，大于1加速，小于1减速
            format: 输出音频格式，默认为None（根据输出文件扩展名自动确定）
            
        Raises:
            FileException: 文件不存在或处理失败时抛出
        
        Examples:
            >>> handler = AudioFileHandler()
            >>> handler.change_speed('input.mp3', 'output.mp3', 1.5)  # 加速50%
            >>> handler.change_speed('input.mp3', 'output.mp3', 0.75)  # 减速25%
        """
        if speed_factor <= 0:
            raise ValueError("速度因子必须大于0")
        
        # 加载音频
        audio = self.load_audio(audio_path)
        
        try:
            # 改变播放速度
            # 通过修改帧率来改变速度
            new_frame_rate = int(audio.frame_rate * speed_factor)
            speed_changed = audio._spawn(audio.raw_data, overrides={
                "frame_rate": new_frame_rate
            })
            
            # 保存音频
            self.save_audio(speed_changed, output_path, format=format)
            logger.info(f"音频速度改变成功: {audio_path} -> {output_path} (速度因子: {speed_factor})")
        except Exception as e:
            raise FileException(f"改变音频速度失败: {e}")
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def change_tempo(self, audio_path: Union[str, Path], output_path: Union[str, Path], 
                    tempo_factor: float, format: str = None) -> None:
        """
        改变音频节奏（不改变音调）
        
        Args:
            audio_path: 输入音频文件路径
            output_path: 输出音频文件路径
            tempo_factor: 节奏因子，大于1加快，小于1减慢
            format: 输出音频格式，默认为None（根据输出文件扩展名自动确定）
            
        Raises:
            FileException: 文件不存在或处理失败时抛出
        
        Examples:
            >>> handler = AudioFileHandler()
            >>> handler.change_tempo('input.mp3', 'output.mp3', 1.5)  # 加快50%
            >>> handler.change_tempo('input.mp3', 'output.mp3', 0.75)  # 减慢25%
        """
        if tempo_factor <= 0:
            raise ValueError("节奏因子必须大于0")
        
        # 加载音频
        audio = self.load_audio(audio_path)
        
        try:
            # 改变节奏需要使用外部工具（如ffmpeg）
            # 首先将音频保存到临时文件
            temp_dir = tempfile.mkdtemp()
            temp_input = Path(temp_dir) / "input.wav"
            temp_output = Path(temp_dir) / "output.wav"
            
            # 保存为WAV格式（便于处理）
            self.save_audio(audio, temp_input, format="wav")
            
            # 使用ffmpeg改变节奏
            import subprocess
            cmd = [
                "ffmpeg", "-y",
                "-i", str(temp_input),
                "-filter:a", f"atempo={tempo_factor}",
                str(temp_output)
            ]
            
            try:
                subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            except subprocess.CalledProcessError as e:
                raise FileException(f"ffmpeg处理失败: {e.stderr.decode() if e.stderr else ''}")
            except FileNotFoundError:
                raise FileException("未找到ffmpeg，请确保已安装并添加到PATH环境变量")
            
            # 加载处理后的音频
            processed_audio = self.AudioSegment.from_file(str(temp_output), format="wav")
            
            # 保存到最终输出路径
            self.save_audio(processed_audio, output_path, format=format)
            
            # 清理临时文件
            try:
                os.remove(temp_input)
                os.remove(temp_output)
                os.rmdir(temp_dir)
            except Exception:
                pass  # 忽略清理错误
            
            logger.info(f"音频节奏改变成功: {audio_path} -> {output_path} (节奏因子: {tempo_factor})")
        except Exception as e:
            raise FileException(f"改变音频节奏失败: {e}")
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def change_pitch(self, audio_path: Union[str, Path], output_path: Union[str, Path], 
                    semitones: float, format: str = None) -> None:
        """
        改变音频音调（不改变速度）
        
        Args:
            audio_path: 输入音频文件路径
            output_path: 输出音频文件路径
            semitones: 半音数量，正值升高音调，负值降低音调
            format: 输出音频格式，默认为None（根据输出文件扩展名自动确定）
            
        Raises:
            FileException: 文件不存在或处理失败时抛出
        
        Examples:
            >>> handler = AudioFileHandler()
            >>> handler.change_pitch('input.mp3', 'output.mp3', 2)  # 升高2个半音
            >>> handler.change_pitch('input.mp3', 'output.mp3', -3)  # 降低3个半音
        """
        # 加载音频
        audio = self.load_audio(audio_path)
        
        try:
            # 改变音调需要使用外部工具（如ffmpeg）
            # 首先将音频保存到临时文件
            temp_dir = tempfile.mkdtemp()
            temp_input = Path(temp_dir) / "input.wav"
            temp_output = Path(temp_dir) / "output.wav"
            
            # 保存为WAV格式（便于处理）
            self.save_audio(audio, temp_input, format="wav")
            
            # 使用ffmpeg改变音调
            import subprocess
            cmd = [
                "ffmpeg", "-y",
                "-i", str(temp_input),
                "-filter:a", f"asetrate=44100*2^({semitones}/12),aresample=44100",
                str(temp_output)
            ]
            
            try:
                subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            except subprocess.CalledProcessError as e:
                raise FileException(f"ffmpeg处理失败: {e.stderr.decode() if e.stderr else ''}")
            except FileNotFoundError:
                raise FileException("未找到ffmpeg，请确保已安装并添加到PATH环境变量")
            
            # 加载处理后的音频
            processed_audio = self.AudioSegment.from_file(str(temp_output), format="wav")
            
            # 保存到最终输出路径
            self.save_audio(processed_audio, output_path, format=format)
            
            # 清理临时文件
            try:
                os.remove(temp_input)
                os.remove(temp_output)
                os.rmdir(temp_dir)
            except Exception:
                pass  # 忽略清理错误
            
            logger.info(f"音频音调改变成功: {audio_path} -> {output_path} (半音: {semitones})")
        except Exception as e:
            raise FileException(f"改变音频音调失败: {e}")
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def apply_filter(self, audio_path: Union[str, Path], output_path: Union[str, Path], 
                    filter_type: str, filter_params: Dict[str, Any] = None, format: str = None) -> None:
        """
        应用音频滤镜
        
        Args:
            audio_path: 输入音频文件路径
            output_path: 输出音频文件路径
            filter_type: 滤镜类型，支持'lowpass'、'highpass'、'bandpass'、'reverb'等
            filter_params: 滤镜参数，默认为None
            format: 输出音频格式，默认为None（根据输出文件扩展名自动确定）
            
        Raises:
            FileException: 文件不存在或处理失败时抛出
            ValueError: 不支持的滤镜类型时抛出
        
        Examples:
            >>> handler = AudioFileHandler()
            >>> # 应用低通滤镜，截止频率为1000Hz
            >>> handler.apply_filter('input.mp3', 'output.mp3', 'lowpass', {'cutoff': 1000})
            >>> # 应用混响效果
            >>> handler.apply_filter('input.mp3', 'output.mp3', 'reverb', {'reverberance': 50})
        """
        # 加载音频
        audio = self.load_audio(audio_path)
        
        # 如果未提供滤镜参数，使用空字典
        if filter_params is None:
            filter_params = {}
        
        try:
            # 应用滤镜需要使用外部工具（如ffmpeg）
            # 首先将音频保存到临时文件
            temp_dir = tempfile.mkdtemp()
            temp_input = Path(temp_dir) / "input.wav"
            temp_output = Path(temp_dir) / "output.wav"
            
            # 保存为WAV格式（便于处理）
            self.save_audio(audio, temp_input, format="wav")
            
            # 构建ffmpeg滤镜字符串
            filter_str = ""
            if filter_type == 'lowpass':
                cutoff = filter_params.get('cutoff', 1000)
                filter_str = f"lowpass=f={cutoff}"
            elif filter_type == 'highpass':
                cutoff = filter_params.get('cutoff', 1000)
                filter_str = f"highpass=f={cutoff}"
            elif filter_type == 'bandpass':
                low_cutoff = filter_params.get('low_cutoff', 500)
                high_cutoff = filter_params.get('high_cutoff', 2000)
                filter_str = f"bandpass=f={low_cutoff}:width_type=h:width={high_cutoff-low_cutoff}"
            elif filter_type == 'reverb':
                reverberance = filter_params.get('reverberance', 50)
                filter_str = f"aecho=0.8:0.9:{reverberance}:0.5"
            elif filter_type == 'echo':
                delay = filter_params.get('delay', 1000)
                decay = filter_params.get('decay', 0.5)
                filter_str = f"aecho=0.8:{decay}:{delay}:0.5"
            elif filter_type == 'equalizer':
                frequency = filter_params.get('frequency', 1000)
                width = filter_params.get('width', 100)
                gain = filter_params.get('gain', 0)
                filter_str = f"equalizer=f={frequency}:width_type=h:width={width}:g={gain}"
            else:
                raise ValueError(f"不支持的滤镜类型: {filter_type}")
            
            # 使用ffmpeg应用滤镜
            import subprocess
            cmd = [
                "ffmpeg", "-y",
                "-i", str(temp_input),
                "-filter:a", filter_str,
                str(temp_output)
            ]
            
            try:
                subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            except subprocess.CalledProcessError as e:
                raise FileException(f"ffmpeg处理失败: {e.stderr.decode() if e.stderr else ''}")
            except FileNotFoundError:
                raise FileException("未找到ffmpeg，请确保已安装并添加到PATH环境变量")
            
            # 加载处理后的音频
            processed_audio = self.AudioSegment.from_file(str(temp_output), format="wav")
            
            # 保存到最终输出路径
            self.save_audio(processed_audio, output_path, format=format)
            
            # 清理临时文件
            try:
                os.remove(temp_input)
                os.remove(temp_output)
                os.rmdir(temp_dir)
            except Exception:
                pass  # 忽略清理错误
            
            logger.info(f"音频滤镜应用成功: {audio_path} -> {output_path} (滤镜: {filter_type})")
        except Exception as e:
            raise FileException(f"应用音频滤镜失败: {e}")
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def extract_channel(self, audio_path: Union[str, Path], output_path: Union[str, Path], 
                       channel: int, format: str = None) -> None:
        """
        提取音频的特定声道
        
        Args:
            audio_path: 输入音频文件路径
            output_path: 输出音频文件路径
            channel: 要提取的声道索引（从0开始）
            format: 输出音频格式，默认为None（根据输出文件扩展名自动确定）
            
        Raises:
            FileException: 文件不存在、声道不存在或处理失败时抛出
        
        Examples:
            >>> handler = AudioFileHandler()
            >>> handler.extract_channel('stereo.mp3', 'left.mp3', 0)  # 提取左声道
            >>> handler.extract_channel('stereo.mp3', 'right.mp3', 1)  # 提取右声道
        """
        # 加载音频
        audio = self.load_audio(audio_path)
        
        try:
            # 检查声道数量
            channels = audio.channels
            if channel < 0 or channel >= channels:
                raise FileException(f"声道索引{channel}超出范围，音频有{channels}个声道")
            
            # 提取特定声道
            if channels == 1:
                # 单声道音频，直接复制
                extracted = audio
            else:
                # 多声道音频，提取指定声道
                extracted = audio.split_to_mono()[channel]
            
            # 保存音频
            self.save_audio(extracted, output_path, format=format)
            logger.info(f"音频声道提取成功: {audio_path} -> {output_path} (声道: {channel})")
        except Exception as e:
            raise FileException(f"提取音频声道失败: {e}")
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def mix_audio(self, audio_paths: List[Union[str, Path]], output_path: Union[str, Path], 
                 weights: List[float] = None, format: str = None) -> None:
        """
        混合多个音频文件
        
        Args:
            audio_paths: 输入音频文件路径列表
            output_path: 输出音频文件路径
            weights: 各音频的权重列表，默认为None（所有音频权重相等）
            format: 输出音频格式，默认为None（根据输出文件扩展名自动确定）
            
        Raises:
            FileException: 文件不存在或混合失败时抛出
        
        Examples:
            >>> handler = AudioFileHandler()
            >>> handler.mix_audio(['vocal.mp3', 'background.mp3'], 'mixed.mp3')
            >>> # 混合时设置不同权重
            >>> handler.mix_audio(['vocal.mp3', 'background.mp3'], 'mixed.mp3', weights=[1.0, 0.5])
        """
        if not audio_paths:
            raise FileException("音频文件路径列表不能为空")
        
        # 如果未提供权重，使用相等权重
        if weights is None:
            weights = [1.0] * len(audio_paths)
        elif len(weights) != len(audio_paths):
            raise FileException("权重列表长度必须与音频文件列表长度相同")
        
        try:
            # 加载所有音频文件
            audio_segments = [self.load_audio(path) for path in audio_paths]
            
            # 找出最长的音频时长
            max_length = max(len(segment) for segment in audio_segments)
            
            # 将所有音频调整为相同长度（填充静音）
            for i in range(len(audio_segments)):
                if len(audio_segments[i]) < max_length:
                    silence = self.AudioSegment.silent(duration=max_length - len(audio_segments[i]))
                    audio_segments[i] += silence
            
            # 应用权重并混合音频
            mixed = audio_segments[0] * weights[0]
            for i in range(1, len(audio_segments)):
                mixed = mixed.overlay(audio_segments[i] * weights[i])
            
            # 保存音频
            self.save_audio(mixed, output_path, format=format)
            logger.info(f"音频混合成功: {len(audio_paths)} 个文件 -> {output_path}")
        except Exception as e:
            raise FileException(f"混合音频失败: {e}")
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def get_audio_info(self, audio_path: Union[str, Path]) -> Dict[str, Any]:
        """
        获取音频信息
        
        Args:
            audio_path: 音频文件路径
            
        Returns:
            Dict[str, Any]: 包含音频信息的字典，包括时长、声道数、采样率、比特率等
            
        Raises:
            FileException: 文件不存在或获取信息失败时抛出
        
        Examples:
            >>> handler = AudioFileHandler()
            >>> info = handler.get_audio_info('example.mp3')
            >>> print(f"音频时长: {info['duration_seconds']} 秒")
            >>> print(f"声道数: {info['channels']}")
        """
        # 加载音频
        audio = self.load_audio(audio_path)
        
        try:
            # 获取基本信息
            duration_ms = len(audio)
            info = {
                'duration_ms': duration_ms,
                'duration_seconds': duration_ms / 1000,
                'channels': audio.channels,
                'sample_width': audio.sample_width,
                'frame_rate': audio.frame_rate,
                'frame_width': audio.frame_width,
                'rms': audio.rms,
                'max_dBFS': audio.max_dBFS,
                'max_possible_amplitude': audio.max_possible_amplitude,
            }
            
            # 获取文件格式和大小
            audio_path = Path(audio_path)
            info['format'] = audio_path.suffix.lstrip('.').lower()
            info['file_size'] = audio_path.stat().st_size
            
            return info
        except Exception as e:
            raise FileException(f"获取音频信息失败: {e}")
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def detect_silence(self, audio_path: Union[str, Path], min_silence_len: int = 1000, 
                      silence_thresh: int = -50) -> List[Tuple[int, int]]:
        """
        检测音频中的静音部分
        
        Args:
            audio_path: 音频文件路径
            min_silence_len: 最小静音长度（毫秒），默认为1000
            silence_thresh: 静音阈值（dBFS），默认为-50
            
        Returns:
            List[Tuple[int, int]]: 静音部分的起始和结束时间（毫秒）列表
            
        Raises:
            FileException: 文件不存在或检测失败时抛出
        
        Examples:
            >>> handler = AudioFileHandler()
            >>> silence_ranges = handler.detect_silence('example.mp3')
            >>> for start, end in silence_ranges:
            ...     print(f"静音: {start}ms - {end}ms")
        """
        # 加载音频
        audio = self.load_audio(audio_path)
        
        try:
            from pydub.silence import detect_silence
            
            # 检测静音部分
            silence_ranges = detect_silence(audio, min_silence_len=min_silence_len, silence_thresh=silence_thresh)
            
            logger.debug(f"音频静音检测成功: {audio_path} (检测到 {len(silence_ranges)} 个静音部分)")
            return silence_ranges
        except Exception as e:
            raise FileException(f"检测音频静音部分失败: {e}")
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def remove_silence(self, audio_path: Union[str, Path], output_path: Union[str, Path], 
                      min_silence_len: int = 1000, silence_thresh: int = -50, 
                      format: str = None) -> None:
        """
        移除音频中的静音部分
        
        Args:
            audio_path: 输入音频文件路径
            output_path: 输出音频文件路径
            min_silence_len: 最小静音长度（毫秒），默认为1000
            silence_thresh: 静音阈值（dBFS），默认为-50
            format: 输出音频格式，默认为None（根据输出文件扩展名自动确定）
            
        Raises:
            FileException: 文件不存在或处理失败时抛出
        
        Examples:
            >>> handler = AudioFileHandler()
            >>> handler.remove_silence('input.mp3', 'output.mp3')
            >>> # 自定义静音检测参数
            >>> handler.remove_silence('input.mp3', 'output.mp3', min_silence_len=500, silence_thresh=-40)
        """
        # 加载音频
        audio = self.load_audio(audio_path)
        
        try:
            from pydub.silence import detect_silence
            
            # 检测静音部分
            silence_ranges = detect_silence(audio, min_silence_len=min_silence_len, silence_thresh=silence_thresh)
            
            # 如果没有检测到静音，直接保存原始音频
            if not silence_ranges:
                self.save_audio(audio, output_path, format=format)
                logger.info(f"未检测到静音部分: {audio_path} -> {output_path}")
                return
            
            # 创建非静音部分的列表
            non_silence_ranges = []
            audio_length = len(audio)
            
            # 添加第一个非静音部分（如果存在）
            if silence_ranges[0][0] > 0:
                non_silence_ranges.append((0, silence_ranges[0][0]))
            
            # 添加中间的非静音部分
            for i in range(len(silence_ranges) - 1):
                non_silence_ranges.append((silence_ranges[i][1], silence_ranges[i+1][0]))
            
            # 添加最后一个非静音部分（如果存在）
            if silence_ranges[-1][1] < audio_length:
                non_silence_ranges.append((silence_ranges[-1][1], audio_length))
            
            # 提取并连接非静音部分
            if non_silence_ranges:
                non_silence_audio = [audio[start:end] for start, end in non_silence_ranges]
                result = sum(non_silence_audio)
                
                # 保存音频
                self.save_audio(result, output_path, format=format)
                logger.info(f"音频静音移除成功: {audio_path} -> {output_path} (移除了 {len(silence_ranges)} 个静音部分)")
            else:
                # 如果全是静音，创建一个短的静音音频
                result = self.AudioSegment.silent(duration=100)
                self.save_audio(result, output_path, format=format)
                logger.warning(f"音频全部是静音: {audio_path} -> {output_path}")
        except Exception as e:
            raise FileException(f"移除音频静音部分失败: {e}")
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def normalize_audio(self, audio_path: Union[str, Path], output_path: Union[str, Path], 
                       target_dBFS: float = -20.0, format: str = None) -> None:
        """
        标准化音频音量
        
        Args:
            audio_path: 输入音频文件路径
            output_path: 输出音频文件路径
            target_dBFS: 目标音量级别（dBFS），默认为-20.0
            format: 输出音频格式，默认为None（根据输出文件扩展名自动确定）
            
        Raises:
            FileException: 文件不存在或处理失败时抛出
        
        Examples:
            >>> handler = AudioFileHandler()
            >>> handler.normalize_audio('input.mp3', 'output.mp3')
            >>> handler.normalize_audio('input.mp3', 'output.mp3', target_dBFS=-15.0)
        """
        # 加载音频
        audio = self.load_audio(audio_path)
        
        try:
            # 计算当前音量与目标音量的差值
            change_in_dBFS = target_dBFS - audio.dBFS
            
            # 标准化音量
            normalized = audio.apply_gain(change_in_dBFS)
            
            # 保存音频
            self.save_audio(normalized, output_path, format=format)
            logger.info(f"音频音量标准化成功: {audio_path} -> {output_path} (目标音量: {target_dBFS} dBFS)")
        except Exception as e:
            raise FileException(f"标准化音频音量失败: {e}")
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def audio_to_mono(self, audio_path: Union[str, Path], output_path: Union[str, Path], 
                     format: str = None) -> None:
        """
        将音频转换为单声道
        
        Args:
            audio_path: 输入音频文件路径
            output_path: 输出音频文件路径
            format: 输出音频格式，默认为None（根据输出文件扩展名自动确定）
            
        Raises:
            FileException: 文件不存在或转换失败时抛出
        
        Examples:
            >>> handler = AudioFileHandler()
            >>> handler.audio_to_mono('stereo.mp3', 'mono.mp3')
        """
        # 加载音频
        audio = self.load_audio(audio_path)
        
        try:
            # 转换为单声道
            mono_audio = audio.set_channels(1)
            
            # 保存音频
            self.save_audio(mono_audio, output_path, format=format)
            logger.info(f"音频转换为单声道成功: {audio_path} -> {output_path}")
        except Exception as e:
            raise FileException(f"转换音频为单声道失败: {e}")
    
    @exception_handler(exception_type=Exception, reraise_as=FileException)
    def audio_to_stereo(self, audio_path: Union[str, Path], output_path: Union[str, Path], 
                       format: str = None) -> None:
        """
        将音频转换为立体声
        
        Args:
            audio_path: 输入音频文件路径
            output_path: 输出音频文件路径
            format: 输出音频格式，默认为None（根据输出文件扩展名自动确定）
            
        Raises:
            FileException: 文件不存在或转换失败时抛出
        
        Examples:
            >>> handler = AudioFileHandler()
            >>> handler.audio_to_stereo('mono.mp3', 'stereo.mp3')
        """
        # 加载音频
        audio = self.load_audio(audio_path)
        
        try:
            # 如果已经是立体声，直接保存
            if audio.channels == 2:
                self.save_audio(audio, output_path, format=format)
                logger.info(f"音频已经是立体声: {audio_path} -> {output_path}")
                return
            
            # 转换为立体声（将单声道复制到两个声道）
            stereo_audio = audio.set_channels(2)
            
            # 保存音频
            self.save_audio(stereo_audio, output_path, format=format)
            logger.info(f"音频转换为立体声成功: {audio_path} -> {output_path}")
        except Exception as e:
            raise FileException(f"转换音频为立体声失败: {e}")